package com.nowcoder.community.controller;

import com.google.code.kaptcha.Producer;
import com.nowcoder.community.pojo.User;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.CommunityConstant;
import com.nowcoder.community.util.CommunityUtil;
import com.nowcoder.community.util.RedisKeyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Api(description = "登录相关")
@Controller
public class LoginController implements CommunityConstant {

    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

//    @Autowired
//    @Qualifier("discussPostService")
//    DiscussPostService discussPostService;

    @Autowired
    @Qualifier("kaptchaProducer")
    private Producer kaptchaProducer;

    @Autowired
    @Qualifier("userService")
    private UserService userService;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @ApiOperation(value = "跳转到注册页面接口")
    @GetMapping("/register")
    public String getRegistPage(){
        return "/site/register";
    }

    @ApiOperation(value = "跳转到登录页面接口")
    @GetMapping("/login")
    public String getLoginPage(){
        return "/site/login";
    }

    @ApiOperation(value = "注册功能实现接口")
    @PostMapping("/register")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "user", value = "注册的用户实例")
    })
    public String register(Model model, User user){
        //SpringMVC中会实例化请求方法中的接收参数Model model和User user，并且会自动将user注入到model中
        Map<String, Object> map = userService.register(user);
        if (map==null || map.isEmpty()){//map.isEmpty()：表示容器中没有元素，是个空容器
            model.addAttribute("msg", "注册成功，我们已经向您的邮箱发送了一封邮件，请尽快激活");
            model.addAttribute("target", "/index");
            return "site/operate-result";//此页面是显示注册结果
        }else {  //map != null ，注册失败
            model.addAttribute("usernameMsg", map.get("usernameMsg"));
            model.addAttribute("passwordMsg", map.get("passwordMsg"));
            model.addAttribute("emailMsg", map.get("emailMsg"));
            return "site/register";
        }

    }

    //http://localhost:8080/community/activation/101/code
    @ApiOperation(value = "激活功能实现接口")
    @GetMapping("/activation/{userId}/{code}")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "激活的用户id"),
            @ApiImplicitParam(name = "code", value = "激活码")
    })
    public String activation(Model model, @PathVariable("userId") int userId,@PathVariable("code") String code){
        int result = userService.activation(userId, code);
        if (result == ACTIVATION_SUCCESS){
            model.addAttribute("msg", "注册成功，您的账号可以正常使用了！");
            model.addAttribute("target", "/login");
        }else if (result == ACTIVATION_REPEAT){
            model.addAttribute("msg", "无效操作，该账号已经激活过了！");
            model.addAttribute("target", "/index");
        }else{
            model.addAttribute("msg", "激活失败，提供的激活码不正确！");
            model.addAttribute("target", "/index");
        }
        return "site/operate-result";
    }

    /*在login.html页面中时会发送这个生成验证码的请求，此接口就是用于生成验证码*/
    @ApiOperation(value = "服务器生成验证码接口")
    @GetMapping("/kaptcha")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "response", value = "服务器的响应实例")
    })
    public void getKaptcha(HttpServletResponse response/*, HttpSession session*/){
//        System.out.println("-----" + kaptchaProducer);

        //生成验证码
        String text = kaptchaProducer.createText();
//        System.out.println("text--------" + text);

        //根据验证码生成验证码的图片
        BufferedImage image = kaptchaProducer.createImage(text);

        //将验证码存入session
//        session.setAttribute("kaptcha", text);

        String kaptchaOwner = CommunityUtil.generateUUID();
        //kaptchaOwner生成后存放到cookie中
        Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
        //设置cookie的存活时间
        cookie.setMaxAge(60);
        //设置cookie的有效路径
        cookie.setPath(contextPath);
        response.addCookie(cookie);

        //获取存放在Redis中的验证码的key
        String kaptchaRedisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
        //将验证码存入到Redis中（验证码前缀+kaptchaRedisKey作为验证码的key，value为验证码）
        //设置验证码的有效时间为60秒
        redisTemplate.opsForValue().set(kaptchaRedisKey, text, 60, TimeUnit.SECONDS);

        //将图片响应给浏览器（以png格式输出）
        response.setContentType("/image/png");

        try {
            OutputStream os = response.getOutputStream();
            ImageIO.write(image, "png",os);
        } catch (IOException e) {
            logger.error("响应验证码失败：" + e.getMessage());
        }

    }

    @ApiOperation(value = "用户登录接口")
    @PostMapping("/login")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "输入的用户名"),
            @ApiImplicitParam(name = "password", value = "输入密码"),
            @ApiImplicitParam(name = "code", value = "用户输入的验证码"),
            @ApiImplicitParam(name = "rememberMe", value = "登录时记住我的功能"),
            @ApiImplicitParam(name = "response", value = "服务器的响应实例"),
            @ApiImplicitParam(name = "kaptchaOwner", value = "存放在Redis中的验证码的key")
    })
    public String login(String username, String password, String code, boolean rememberMe,
                        Model model, /*HttpSession session,*/ HttpServletResponse response,
                        @CookieValue("kaptchaOwner") String kaptchaOwner){
        //检查验证码（获得的验证码为空或者是输入的验证码，或者是验证码不正确）
//        String kaptcha = (String) session.getAttribute("kaptcha");

        //从Redis中获取验证码
        String kaptcha = null;
        //kaptchaOwner是从cookie中获取到的，如果还有效就从Redis中获取验证码
        if(StringUtils.isNotBlank(kaptchaOwner)){
            String kaptchaRedisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);

            kaptcha = (String) redisTemplate.opsForValue().get(kaptchaRedisKey);
        }

        //获取到的验证码为空或输入的验证码为空或者是两者不相等
        if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
            model.addAttribute("codeMsg", "验证码不正确！");
            return "site/login";
        }

        int expireSeconds = rememberMe ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
        Map<String, Object> map = userService.login(username, password, expireSeconds);

        //如果有凭证时，登录后设置cookie
        /*
         * Cookie对象的名字不能是中文，Cookie对象的值可以是中文但是需要指定的字符集进行编码，
         * 而且获取Cookie对象还需要指定的字符集进行解码
         */
        if (map.containsKey("ticket")){
            Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
            cookie.setPath(contextPath);
            cookie.setMaxAge(expireSeconds);//cookie的最大有效时间
//            System.out.println("cookie的最大有效时间" + cookie.getMaxAge());
            response.addCookie(cookie);

            //登录成功后返回用户主页
            return "redirect:/index";
//            return "forward:/index";
        }else {
            //没有凭证时，只使用
            model.addAttribute("usernameMsg", map.get("usernameMsg"));
            model.addAttribute("passwordMsg", map.get("passwordMsg"));
            return "site/login";
        }

    }

    @ApiOperation(value = "用户退出登录接口")
    @GetMapping("/exit")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "ticket", value = "用户的登录凭证")
    })
    public String exit(@CookieValue("ticket") String ticket){
        userService.exit(ticket);
        SecurityContextHolder.clearContext();
        return "redirect:/login";
    }

    @GetMapping("/logout")
    public String logout(){
        //此处应该将用户以及这个用户发过的帖子、评论等全部删除，将消息中的status置为2，表示删除
        return "redirect:/login";
    }

}
